﻿using H.Cmd;
using H.Win32.Diagnostics;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;

namespace H.Loader
{
    internal class Program
    {

        public static void DisplayHelper()
        {
            Console.WriteLine("<exe> [.../pid <pid>] [.../proc <procName>] [.../exe <exeFile>] [/x86] <exeFile [...args]> [...[$ <exeFile> [...args]]]");
        }


        /// <summary>
        /// 如果运行成功,返回0,没有执行返回-1,执行失败大于0
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public static int Main(string[] args)
        {
            Arguments arguments = new Arguments(args);
            if (arguments.Count == 0)
            {
                DisplayHelper();
                return 0;
            }

            int maxIndex = 1;
            //更新最后一个必填项的开始位置
            int updateMaxIndex(int index, int appendCount)
            {
                if (index != -1)
                {
                    maxIndex = Math.Max(index + appendCount + 1, maxIndex);
                }
                return index;
            }

            IEnumerable<string> procNames = from i in arguments.GetNamedOptions("/proc", 0, 1, ref maxIndex) select i[0];
            IEnumerable<string> exePaths = from i in arguments.GetNamedOptions("/exe", 0, 1, ref maxIndex) select i[0];
            IEnumerable<string> pids = from i in arguments.GetNamedOptions("/pid", 0, 1, ref maxIndex) select i[0];

            bool is32Bit = updateMaxIndex(arguments.IndexOfOption("/x86"), 0) != -1;

            //存储所有需要启动的APP的信息
            List<KeyValuePair<string, string[]>> exeList = new List<KeyValuePair<string, string[]>>();
            int cursor = maxIndex;
            while (cursor < arguments.Count)
            {
                string exeFile = arguments[cursor++];
                string[] exeArgs;
                int nextExe = arguments.IndexOfOption("$", cursor);
                if (nextExe == -1)
                {
                    exeArgs = arguments.GetOptions(cursor);
                }
                else
                {
                    exeArgs = arguments.GetOptions(cursor, nextExe - cursor);
                }
                exeList.Add(new KeyValuePair<string, string[]>(exeFile, exeArgs));
                if (nextExe == -1)
                {
                    break;
                }
                cursor = nextExe + 1;
            }

            string argument = $"{AppDomain.CurrentDomain.BaseDirectory}#{string.Join("#", from kv in exeList select $"{kv.Key}|{string.Join("|", kv.Value)}")}";

            string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "lib\\hrth.exe");
            MethodInfo methodInfo = Assembly.ReflectionOnlyLoad(File.ReadAllBytes(dllPath))?.EntryPoint;
            if (methodInfo == null)
            {
                Console.WriteLine("核心模块缺失,程序无法运行");
                return 0;
            }

            bool InjectInternal(uint pid)
            {
                return Injector.InjectManaged(pid, dllPath, methodInfo.DeclaringType.FullName, methodInfo.Name, argument);
            }

            foreach (string pid in pids)
            {
                if (int.TryParse(pid, out int pidNum))
                {
                    Process process = Process.GetProcessById(pidNum);
                    if (is32Bit)
                    {
                        //判断指定的进程是否为32位进程
                        if (!Process32.Is64BitProcess((uint)process.Id, out bool is64) || is64)
                        {
                            continue;
                        }
                    }

                    if (process != null)
                    {
                        if (InjectInternal((uint)process.Id))
                        {
                            Console.WriteLine($"Had Injected Into {process.ProcessName}[{process.Id}]");
                            return 0;
                        }
                    }
                }
            }


            foreach (string procName in procNames)
            {
                foreach (Process process in Process.GetProcessesByName(procName))
                {
                    if (is32Bit)
                    {
                        //判断指定的进程是否为32位进程
                        if (!Process32.Is64BitProcess((uint)process.Id, out bool is64) || is64)
                        {
                            continue;
                        }
                    }
                    if (InjectInternal((uint)process.Id))
                    {
                        Console.WriteLine($"Had Injected Into {process.ProcessName}[{process.Id}]");
                        return 0;
                    }
                }
            }

            foreach (string exePath in exePaths)
            {
                if (File.Exists(exePath))
                {
                    if (!Injector.Is64BitPE(exePath, out bool is64))
                    {
                        continue;
                    }
                    Process process = Process.Start(new ProcessStartInfo(exePath) { WindowStyle = ProcessWindowStyle.Minimized });
                    if (process != null)
                    {
                        if (InjectInternal((uint)process.Id))
                        {
                            Console.WriteLine($"Had Injected Into {process.ProcessName}[{process.Id}]");
                            return 0;
                        }
                    }
                }
            }


            return -1;
        }


    }
}
